﻿// <copyright file="LogicalExpressionSyntax.cs" company="http://www.dymetis.com">
//
// Copyright (c) 2011 Eddie Z. Lin.
//
// This source is subject to the Microsoft Public License.
// See http://www.opensource.org/licenses/ms-pl.
// All other rights reserved.
// 
// </copyright>

namespace Dymetis.Expressions
{
    using System.Collections.Generic;
    using System.Linq;

    public sealed class LogicalExpressionSyntax
    {
        private static readonly LogicalExpressionSyntax @default;

        private static readonly LogicalExpressionSyntax eventFilter;
        private static readonly LogicalExpressionSyntax extendedEventFilter;

        static LogicalExpressionSyntax()
        {
            var nonLiteralTokens = new Dictionary<string, LogicalExpressionToken>();
            nonLiteralTokens["+"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorAdd, null);
            nonLiteralTokens["-"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorSubtract, null);
            nonLiteralTokens["<"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorLessThan, null);
            nonLiteralTokens["<="] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorLessThanEqual, null);
            nonLiteralTokens[">"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorGreaterThan, null);
            nonLiteralTokens[">="] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorGreaterThanEqual, null);
            nonLiteralTokens["="] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorEqual, null);
            nonLiteralTokens["<>"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorNotEqual, null);

            var literalTokens = new Dictionary<string, LogicalExpressionToken>();
            literalTokens["null"] = new LogicalExpressionToken(LogicalExpressionTokenType.ConstantNull, null);
            literalTokens["today"] = new LogicalExpressionToken(LogicalExpressionTokenType.ConstantToday, null);
            literalTokens["date"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorDate, null);
            literalTokens["and"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorAnd, null);
            literalTokens["or"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorOr, null);
            literalTokens["not"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorNot, null);
            literalTokens["under"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorUnder, null);
            literalTokens["match"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorMatch, null);
            literalTokens["like"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorLike, null);

            extendedEventFilter = new LogicalExpressionSyntax()
            {
                StringDelimiter = '"',
                AltStringDelimiter = '\'',
                VariableIndicator = '$',
                GroupBegin = '(',
                GroupEnd = ')',
                NonLiteralTokens = nonLiteralTokens.ToList().AsReadOnly(),
                LiteralTokens = literalTokens.ToList().AsReadOnly(),
            };

            eventFilter = (LogicalExpressionSyntax)extendedEventFilter.MemberwiseClone();
            eventFilter.LeftOperandAsVariable = true;

            nonLiteralTokens = new Dictionary<string, LogicalExpressionToken>();

            // TODO: Addition and substraction support.
            ////nonLiteralTokens["+"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorAdd, null);
            ////nonLiteralTokens["-"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorSubtract, null);

            nonLiteralTokens["<"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorLessThan, null);
            nonLiteralTokens["<="] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorLessThanEqual, null);
            nonLiteralTokens[">"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorGreaterThan, null);
            nonLiteralTokens[">="] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorGreaterThanEqual, null);
            nonLiteralTokens["=="] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorEqual, null);
            nonLiteralTokens["!="] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorNotEqual, null);

            literalTokens = new Dictionary<string, LogicalExpressionToken>();
            literalTokens["and"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorAnd, null);
            literalTokens["or"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorOr, null);
            literalTokens["not"] = new LogicalExpressionToken(LogicalExpressionTokenType.OperatorNot, null);

            @default = new LogicalExpressionSyntax()
            {
                StringDelimiter = '"',
                AltStringDelimiter = '\'',
                VariableIndicator = '$',
                GroupBegin = '(',
                GroupEnd = ')',
                NonLiteralTokens = nonLiteralTokens.ToList().AsReadOnly(),
                LiteralTokens = literalTokens.ToList().AsReadOnly(),
            };
        }

        private LogicalExpressionSyntax()
        {
        }

        public static LogicalExpressionSyntax Default
        {
            get
            {
                return @default;
            }
        }

        public static LogicalExpressionSyntax EventFilter
        {
            get
            {
                return eventFilter;
            }
        }

        public static LogicalExpressionSyntax ExtendedEventFilter
        {
            get
            {
                return extendedEventFilter;
            }
        }

        internal char StringDelimiter
        {
            get;
            private set;
        }

        internal char AltStringDelimiter
        {
            get;
            private set;
        }

        internal char VariableIndicator
        {
            get;
            private set;
        }

        internal char GroupBegin
        {
            get;
            private set;
        }

        internal char GroupEnd
        {
            get;
            private set;
        }

        internal bool LeftOperandAsVariable
        {
            get;
            private set;
        }

        internal IList<KeyValuePair<string, LogicalExpressionToken>> NonLiteralTokens
        {
            get;
            private set;
        }

        internal IList<KeyValuePair<string, LogicalExpressionToken>> LiteralTokens
        {
            get;
            private set;
        }

        internal string GetOperator(LogicalExpressionTokenType token)
        {
            return this.NonLiteralTokens.Union(this.LiteralTokens).Single(t => t.Value.TokenType == token).Key;
        }
    }
}
